package com.rookie.opcua.task;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.rookie.opcua.client.ClientGen;
import com.rookie.opcua.dto.ServerStatusDTO;
import com.rookie.opcua.dto.SimulationDTO;
import com.rookie.opcua.entity.DataSimulation;
import com.rookie.opcua.entity.NodeStructure;
import com.rookie.opcua.mapper.DataSimluationMapper;
import com.rookie.opcua.mapper.NodeStructureMapper;
import com.rookie.opcua.service.DataSimulationService;
import com.rookie.opcua.utils.JsonUtils;
import com.rookie.opcua.utils.MapObjUtil;
import com.rookie.opcua.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.model.nodes.objects.ServerNode;
import org.eclipse.milo.opcua.sdk.client.model.nodes.variables.ServerStatusNode;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.enumerated.ServerState;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;


/**
 * @author yugo
 */
@Component
@Slf4j
public class OpcUaReadNodeTask {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private NodeStructureMapper nodeStructureMapper;

    @Async
    @Scheduled(cron = "0/30 * * * * ?")
    public void setReadNodeSupport() {
        try {
            log.info("获取节点状态信息");
            OpcUaClient client = ClientGen.opcUaClient;
            client.connect().get();

            // 获取对服务器对象的类型化引用 ：服务节点
            ServerNode serverNode = client.getAddressSpace().getObjectNode(
                    Identifiers.Server,
                    ServerNode.class
            ).get();

            // 读取服务器对象的属性
            String[] serverArray = serverNode.getServerArray().get();

            ServerStatusNode serverStatusNode = serverNode.getServerStatusNode().get();
            DateTime startTime = serverStatusNode.getStartTime().get();
            DateTime currentTime = serverStatusNode.getCurrentTime().get();
            ServerState state = serverStatusNode.getState().get();

            ServerStatusDTO serverStatusDTO = new ServerStatusDTO();
            serverStatusDTO.setState(state.name());
            serverStatusDTO.setStartTime(startTime.getJavaDate());
            serverStatusDTO.setCurrentTime(currentTime.getJavaDate());
            serverStatusDTO.setServerArray(serverArray[0]);

            redisTemplate.opsForValue().set("SERVER_NODE", JsonUtils.beanToJson(serverStatusDTO));
        } catch (Exception e) {
            log.error("获取服务节点失败,错误信息：{}", e.getMessage());
            e.printStackTrace();
        }
    }

    @Autowired
    private DataSimluationMapper dataSimluationMapper;

    @Autowired
    private DataSimulationService dataSimulationService;

    //demo  读取所有模拟数据
//    @Scheduled(cron = "0/30 * * * * ?")
    public void setSimulation() {
        try {
            log.info("获取 Simulation 模拟信息模型数据");
//            List<SimulationDTO> simulationList = null;
            OpcUaClient client = ClientGen.opcUaClient;
            client.connect().get();
            //["Server","MyObjects","StaticData","NonUaNodeComplianceTest","Simulation","MyBigNodeManager"]

            //取nameSpaceIndex 为5的 下面所有数据
            Integer nameSpaceIndex = 5;

            //读取nameSpaceIndex = 5  的数据
            List<NodeStructure> nodeIds = nodeStructureMapper.selectList(new LambdaQueryWrapper<NodeStructure>()
                    .eq(NodeStructure::getNamespaceIndex, nameSpaceIndex)
                    .ne(NodeStructure::getLevel, 0));

//            Map<String, Object> map = new HashMap<>();
            ArrayList<DataSimulation> nodeList = Lists.newArrayList();
            nodeIds.stream().parallel().forEach(node -> {
                NodeId one = new NodeId(node.getNamespaceIndex(), node.getDisplayName());
                try {
//                    System.out.println(client.getNamespaceTable());
                    DataValue dataValue = client.readValue(0.0, TimestampsToReturn.Both, one).get();
//                    map.put(nodeId, dataValue.getValue().getValue().toString());
//                    System.out.println("nodeId = " + nodeId + ";  dataValue = " + dataValue);
                    //插入数据库
                    DataSimulation dataSimulation = new DataSimulation();
                    dataSimulation.setName(node.getDisplayName());
                    dataSimulation.setValue(dataValue.getValue().getValue().toString());
                    dataSimulation.setNamespaceIndex(one.getNamespaceIndex().intValue());
                    dataSimulation.setTimestamp(dataValue.getSourceTime().getJavaDate());

                    nodeList.add(dataSimulation);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            dataSimulationService.saveBatch(nodeList);
            //map与实体转换
//            SimulationDTO simulationDTO = MapObjUtil.map2Object(map, SimulationDTO.class);
            //Hutool
/*            SimulationDTO simulationDTO = BeanUtil.mapToBean(map,SimulationDTO.class,true);

            Object simulationRecord = redisTemplate.opsForValue().get("SIMULATION");
            if (simulationRecord != null) {
                simulationList = JsonUtils.jsonToList(simulationRecord.toString(), SimulationDTO.class);
            } else {
                simulationList = new ArrayList<>();
            }
            simulationList.add(simulationDTO);*/

            //放入redis
//            redisTemplate.opsForValue().set("SIMULATION", JsonUtils.listToJson(simulationList));

            //webservice 推送
//            WebSocketServer.sendInfo(JsonUtils.listToJson(simulationList));
        } catch (Exception e) {
            log.error("获取模拟服务节点失败，错误信息{}", e.getMessage());
            e.printStackTrace();
        }
    }
}
